#include "StaticJavaLib.h"
#include "gc.h"

struct Data{
  int i;
};

struct LinkedNode{
  struct Data* data;
  struct LinkedNode* next;
};

struct LinkedList{
  struct LinkedNode* head;
  struct LinkedNode* last;
  int size;
};

struct Queue{
};

struct LinkedList* Queue_llNewLinkedList(){
  struct LinkedList* result;
  gc_add_root_node(&result);
  result = (struct LinkedList*)gc_malloc(sizeof(struct LinkedList));
  result->head = (struct LinkedNode*)gc_malloc(sizeof(struct LinkedNode));
  result->last = result->head;
  gc_free_root_node(&result);
  return result;
}

bool Queue_llIsEmpty(struct LinkedList* ll){
  StaticJavaLib_assertTrue(ll != NULL);
  return ll->size == 0;
}

void Queue_llAddLast(struct LinkedList* ll,struct Data* data){
  StaticJavaLib_assertTrue(ll != NULL && data != NULL);
  ll->last->next = (struct LinkedNode*)gc_malloc(sizeof(struct LinkedNode));
  ll->last = ll->last->next;
  ll->last->data = data;
  ll->size++;
  gc_recycle();
}

struct Data* Queue_llRemoveFirst(struct LinkedList* ll){
  struct Data* result;
  gc_add_root_node(&result);
  StaticJavaLib_assertTrue(ll->size > 0);
  result = ll->head->next->data;
  ll->head = ll->head->next;
  ll->size--;
  gc_free_root_node(&result);
  return result;
}

void main(int argc,char** argv){
  struct LinkedList* ll;
  gc_add_root_node(&ll);
  struct Data* d;
  gc_add_root_node(&d);
  int i;
  ll = Queue_llNewLinkedList();
  for(i = 0;i < 10;i++){
    d = (struct Data*)gc_malloc(sizeof(struct Data));
    d->i = i + 1;
    Queue_llAddLast(ll,d);
    StaticJavaLib_printlni(d->i);
  }
  while(!Queue_llIsEmpty(ll)){
    StaticJavaLib_printlnb(false);
    d = Queue_llRemoveFirst(ll);
    StaticJavaLib_printlnb(true);
  }
  gc_free_root_node(&ll);
  gc_free_root_node(&d);
  gc_recycle();
}
